#include "level.h"

#include <assert.h>
#include <algorithm>

#include "entity.h"

#include "sysEditor.h"
#include "sysGameLoop.h"

#include "ofxXmlSettings.h"

#include "types.h"

//--------------------------------------------------------------------------------------------------

Entity* level_loadEntity(ofxXmlSettings &xml)
{
	Entity* entity = NULL;
	string typeStr = xml.getValue("objectType", "");

	if(!typeStr.empty())
	{
		EntityType entType = getEntTypeEnum(typeStr);
		if(entType != ENT_TYPE_NONE)
			entity = getEntTypeCreateFn(entType)(xml);
	}

	if(entity)
		ofLogNotice("Object loaded: " + entity->name);
	else
		ofLogWarning("Object failed to load!");

	return entity;
}

//--------------------------------------------------------------------------------------------------

Level::Level()
{

}

//--------------------------------------------------------------------------------------------------

void Level::load()
{
	// unload old level first
	destroy();
	// Load from XML file
	ofxXmlSettings xml;

	if(xml.loadFile("level.xml"))
	{
		xml.pushTag("level");
		int objectCount = xml.getNumTags("object");
		for(int i = 0; i < objectCount; i++){
			xml.pushTag("object", i);
			// Load object
			Entity* entity = level_loadEntity(xml);
			if(entity)
				gameObjects.push_back(entity);
			xml.popTag();
		}
	}
	else{
		ofLogError("Level file did not load!");
	}
	ofLogNotice("Level loaded!");

	// Fixup entities
	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		entity->fixup();
	}
}

//--------------------------------------------------------------------------------------------------

void Level::save()
{
	ofxXmlSettings xml;

	// New object
	xml.addTag("level");
	xml.pushTag("level");

	int i = 0;
	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		xml.addTag("object");
		xml.pushTag("object", i);
		Entity* entity = (Entity*)*it;
		entity->save(xml);
		i++;
		xml.popTag();
	}


	xml.saveFile("level.xml");
}

//--------------------------------------------------------------------------------------------------

bool render_sort(Entity* entity1, Entity* entity2)
{

	ofVec3f camPos;
	if(sysEditor_isEnabled())
		camPos = sysGameLoop_getEditorCamera()->getPosition();
	else
		camPos = sysGameLoop_getCamera()->getPosition();

	float dist1 = camPos.distanceSquared(entity1->getPosition());
	float dist2 = camPos.distanceSquared(entity2->getPosition());

	if(entity1->overrideZDepth && !entity2->overrideZDepth)
		return true;
	else if(entity2->overrideZDepth)
		return false;

	if(dist1 > dist2)
		return true;
	else
		return false;
}

void Level::draw()
{
	// Sort entity list
	gameObjects.sort(render_sort);
	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		entity->draw();
	}
}

//-----------------------------------------------------------------------------------------------------------------------

void Level::update(float timeDelta)
{
	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		entity->update(timeDelta);
	}
}

//--------------------------------------------------------------------------------------------------

void Level::destroy()
{
	sysEditor_onLevelClear();
	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		entity->destroy();
		delete(entity);
	}
	gameObjects.clear();
}

//--------------------------------------------------------------------------------------------------

void Level::addEntity(Entity* entity)
{
	gameObjects.push_back(entity);
}

//--------------------------------------------------------------------------------------------------

void Level::deleteEntity(Entity* entity)
{
	list<Entity*>::iterator it = find(gameObjects.begin(), gameObjects.end(), entity);
	gameObjects.remove(*it);
	delete(entity);
}


//--------------------------------------------------------------------------------------------------

Entity* Level::getEntityUnderCursor(int x, int y, ofCamera* camera)
{
	float bestDistance;
	Entity* bestEntity = NULL;

	ofVec3f cursor = ofVec3f(x,y,0);

	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		float distance = cursor.distanceSquared(camera->worldToScreen(entity->getPosition()));
		if(!bestEntity || distance < bestDistance)
		{
			bestEntity = entity;
			bestDistance = distance;
		}
	}

	if(bestEntity && bestDistance < 1000.0f)
		return bestEntity;
	else
		return NULL;
}

//--------------------------------------------------------------------------------------------------

list<Entity*> Level::getEntitiesUnderCursorRect(int x1, int y1, int x2, int y2, ofCamera* camera)
{
	list<Entity*> returnList;

	// Swap the variables so they are always in the same order for
	// simplicities sake
	if(x1 > x2)
	{
		int x3 = x1;
		x1 = x2;
		x2 = x3;
	}
	if(y1 > y2)
	{
		int y3 = y1;
		y1 = y2;
		y2 = y3;
	}

	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		ofVec2f screenCords = camera->worldToScreen(entity->getPosition());

		if(screenCords.x > x1 && screenCords.x < x2 && screenCords.y > y1 && screenCords.y < y2)
			returnList.push_back(entity);
	}

	return returnList;
}

//--------------------------------------------------------------------------------------------------

Entity* Level::getEntity(string name)
{
	for (list<Entity*>::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
	{
		Entity* entity = (Entity*)*it;
		if(entity->name.compare(name) == 0)
			return entity;
	}
	return NULL;
}

//--------------------------------------------------------------------------------------------------